﻿#include "pch.h"
#include "class_tick.h"
#include "class_bars.h"

//定义结构体
struct struct_run
{
	double cash;//现金;
	int  position;//持仓
	double position_value;//持仓价值
	double margen;//保证金
	double fee;//手续费
	double slippage;//滑点
	double total_value;//总权益
	int UpdateTimeMillisec;
	char TradingDay[9];
	char UpdateTime[9];
};


//交易结构体
struct struct_trader
{
	double price;//价格
	double value;//交易价值
	double fee;//手续费
	double slippage;//滑点
	double total_value;//总价值
	int buy;//买入数量
	int sell;//卖出数量
	int position;//最新持仓
	int UpdateMillisec;
	char TradingDay[9];
	char UpdateTime[9];
};


//回测引擎
class class_engine
{
public:
	//成员变量
	double cash;//现金
	double margen;//保证金
	double fee;//手续费
	double slippage;//滑点
	int multiplier;//交易乘数
	int max_position;//最大持仓
	struct_run data_run;
	std::vector<struct_run> data_runs;//容器
	std::vector<struct_trader> data_traders;

	//构造函数
	class_engine(double cash, int multiplier, int max_position, double fee, double slippage)
		:cash(cash), multiplier(multiplier), max_position(max_position), fee(fee), slippage(slippage)
	{
		memset(&data_run, 0, sizeof(struct_run));
		data_run.cash = cash;
	}


	//析构
	~class_engine()
	{
	}


	//执行一次
	void run(const struct_tick& tick, int pos)
	{
		//持仓防超限
		if (pos > max_position)
		{
			pos = max_position;
		}
		else if (pos < -max_position)
		{
			pos = -max_position;
		}
		//计算当前报单数量
		int k = pos - data_run.position;

		if (k != 0)//如果是买入或卖出
		{
			struct_trader data_buy{};//实例化报单结构
			data_buy.buy = k;//买入数量
			data_buy.price = (k > 0 ? tick.AskPrice1 : tick.BidPrice1);//买入价格
			data_buy.fee = std::abs(data_buy.buy) * fee;//手续费
			data_buy.slippage = std::abs(data_buy.buy) * slippage;//滑点
			data_buy.value = data_buy.buy * data_buy.price * multiplier;//买入价值
			data_buy.position = pos;//最终持仓
			data_buy.UpdateMillisec = tick.UpdateMillisec;//毫秒 时间戳
			memcpy(data_buy.TradingDay, tick.TradingDay, 8);//日期 时间戳
			memcpy(data_buy.UpdateTime, tick.UpdateTime, 8);//时分秒 时间戳
			data_traders.push_back(data_buy);//插入交易列表
			data_run.cash -= data_buy.value;//运行现金
			data_run.position = pos;//运行持仓
			data_run.fee += data_buy.fee;//手续费
			data_run.slippage += data_buy.slippage;//划价
		}
		data_run.position = pos;//更新持仓
		data_run.position_value = data_run.position * multiplier * tick.LastPrice;//持仓价值
		data_run.total_value = data_run.cash + data_run.position_value - data_run.fee - data_run.slippage;//总权益
		data_run.UpdateTimeMillisec = tick.UpdateMillisec;//毫秒时间戳
		memcpy(data_run.TradingDay, tick.TradingDay, 8);
		memcpy(data_run.UpdateTime, tick.UpdateTime, 8);//时分秒时间戳
		data_runs.push_back(data_run);//插入容器
		return;
	}


	//评估
	void evaluate(std::string flag_msg)
	{
		std::cout << "交易次数:" << data_traders.size() << std::endl;
		for (auto tr : data_traders)
		{
			//std::cout << tr.TradingDay << " " << tr.UpdateTime << " " << tr.price << " " << tr.buy << " " << tr.position << std::endl;
		}
		char results[1024]{};
		//std::cout << "初始资金:" << cash << ",乘数:" << multiplier << ",最大持仓:" << max_position << ",手续费:" << fee << ",滑点:" << slippage << std::endl;
		//std::cout << "期末现金:" << data_run.cash << ",期末权益:" << data_run.total_value << ",持仓:" << data_run.position << ",持仓权益:" << data_run.position_value << ",手续费:" << data_run.fee << ",滑点:" << data_run.slippage << std::endl;
		double value_h = cash, value_l = cash, value_hc = 0, value_hcb = 0;
		for (auto& rs : data_runs)
		{
			if (rs.total_value > value_h)
			{
				value_h = rs.total_value;
			}
			if (rs.total_value < value_l)
			{
				value_l = rs.total_value;
			}
			if (value_h - rs.total_value > value_hc)
			{
				value_hc = value_h - rs.total_value;
				value_hcb = value_hc / value_h;
			}
		}	

		auto len = snprintf(results, sizeof(results), "标记:%s,权益最高：%g,最低:%g,回撤:%g,比例:%g%%,", flag_msg.c_str(), value_h, value_l, value_hc, value_hcb * 100);
		std::unordered_set<std::string> TradingDays;//天数
		for (auto& rs : data_runs)
		{
			TradingDays.insert(rs.TradingDay);
		}
		int tradings = TradingDays.size();

		len += snprintf(results + len, sizeof(results) - len, "测试天数:%d,收益:%g,收益率:%g%%,年化收益率:%g%%", tradings, data_run.total_value - cash, data_run.total_value / cash * 100 - 100, (data_run.total_value / cash - 1) * 252 / tradings * 100);
//输出结果
		std::lock_guard<std::mutex> g(g_mtx);
		std::ofstream file("result/results.txt", std::ios::app);
		if (file.is_open()) file << results << std::endl;
		std::cout << results<<std::endl;//输出评估结果
		return;
	}

};


//趋势策略
void strategy_trend(int n, class_tick& ticks)
{
	class_engine engine(100000, 10, 5, 4, 10);
	class_bars bars;

	double h1 = 0, h2 = 0, h3 = 0, l1 = 0, l2 = 0, l3 = 0;
	int num = 0;
	int pos = 0;

	for (auto& tick : ticks.datas)
	{
		CThostFtdcDepthMarketDataField data{};
		data.LastPrice = tick.LastPrice;
		data.AskPrice1 = tick.AskPrice1;
		data.BidPrice1 = tick.BidPrice1;
		strncpy(data.TradingDay, tick.TradingDay, 8);
		data.TradingDay[8] = '\0';
		strncpy(data.UpdateTime, tick.UpdateTime, 8);
		data.UpdateTime[8] = '\0';

		bars.insert(data);

		// 仅在 bar 数量增加且足够时更新指标
		if (static_cast<int>(bars.datas.size()) > num)
		{
			num = bars.datas.size();
			if (bars.datas.size() >= static_cast<size_t>(n * 3))
			{
				h1 = bars.highest(n * 2, n * 3);
				h2 = bars.highest(n, n * 2);
				h3 = bars.highest(0, n);
				l1 = bars.lowest(n * 2, n * 3);
				l2 = bars.lowest(n, n * 2);
				l3 = bars.lowest(0, n);

				if (h3 > h2 && h2 > h1 && l3 > l2 && l2 > l1)
				{
					pos = 1;  // 多头趋势
				}
				else if (l3 < l2 && l2 < l1 && h3 < h2 && h2 < h1) {
					pos = -1; // 空头趋势
				}
			}
		}

		engine.run(tick, pos);  // 每个 tick 执行，但信号基于 bar
	}

	engine.evaluate(std::to_string(n));
	return;
}


//主函数
int main()
{
	
	//建立目录
	create_path("result");
	create_path("configuration");
	//读取配置文件
	auto configs = read_csv("configuration/config.txt");

	//实例化tick类
	class_tick ts;

	//解析
	for (auto& config : configs)
	{
		if (config.size() == 2 && config[0] == "file_name")
		{
				ts.read(config[1], 100000000);
		}
	}

	if (ts.datas.size() == 0)
	{
		std::cout << "数据太少" << std::endl;
		return 0;
	}


	//执行
	for (int i = 25; i < 700; i += 5)
	{
		pool1().detach_task([i, &ts] {strategy_trend(i, ts); });
	}
	int time_num = 0;//时间
	while (!pool1().wait_for(std::chrono::seconds(10)))
	{
		time_num += 10;
		std::cout << "已用时间:"<<time_num<<"秒,当前任务数量:" << pool1().get_tasks_total() << std::endl;
	}

	return 0;
}
